from flask import Flask, request, jsonify, render_template
from flask_cors import CORS
from config import Config
from models import db, Item, Relation
from kg_extractor import kg_extractor
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def create_app():
    """创建Flask应用"""
    app = Flask(__name__)
    app.config.from_object(Config)
    
    # 初始化扩展
    db.init_app(app)
    CORS(app)  # 启用跨域支持
    
    # 创建数据表
    with app.app_context():
        try:
            db.create_all()
            logger.info("数据库表创建成功")
        except Exception as e:
            logger.error(f"数据库连接失败: {e}")
    
    return app

app = create_app()

# 首页路由
@app.route('/')
def index():
    """首页"""
    return render_template('index.html')

# API路由
@app.route('/api/items', methods=['GET'])
def get_items():
    """获取所有物品"""
    try:
        items = Item.query.all()
        return jsonify({
            'success': True,
            'data': [item.to_dict() for item in items],
            'count': len(items)
        })
    except Exception as e:
        logger.error(f"获取物品列表失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/items', methods=['POST'])
def create_item():
    """创建新物品"""
    try:
        data = request.get_json()
        if not data or not data.get('name'):
            return jsonify({'success': False, 'message': '物品名称不能为空'}), 400
        
        name = data['name'].strip()
        if not name:
            return jsonify({'success': False, 'message': '物品名称不能为空'}), 400
        
        # 检查是否已存在
        existing_item = Item.query.filter_by(name=name).first()
        if existing_item:
            return jsonify({'success': False, 'message': '物品已存在'}), 400
        
        # 创建新物品
        item = Item(name=name)
        db.session.add(item)
        db.session.commit()
        
        logger.info(f"创建物品成功: {item.name}")
        return jsonify({'success': True, 'data': item.to_dict()}), 201
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"创建物品失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/relations', methods=['GET'])
def get_relations():
    """获取所有关系"""
    try:
        relations = Relation.query.all()
        return jsonify({
            'success': True,
            'data': [relation.to_dict() for relation in relations],
            'count': len(relations)
        })
    except Exception as e:
        logger.error(f"获取关系列表失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/relations', methods=['POST'])
def create_relation():
    """创建新关系"""
    try:
        data = request.get_json()
        if not data:
            return jsonify({'success': False, 'message': '请求数据不能为空'}), 400
        
        source_item_id = data.get('source_item_id')
        target_item_id = data.get('target_item_id')
        relation_type = data.get('relation_type', 'related_to')
        description = data.get('description', '')
        
        # 验证必需字段
        if not source_item_id or not target_item_id:
            return jsonify({'success': False, 'message': '源物品ID和目标物品ID不能为空'}), 400
        
        # 检查物品是否存在
        source_item = Item.query.get(source_item_id)
        target_item = Item.query.get(target_item_id)
        
        if not source_item:
            return jsonify({'success': False, 'message': f'源物品ID {source_item_id} 不存在'}), 400
        if not target_item:
            return jsonify({'success': False, 'message': f'目标物品ID {target_item_id} 不存在'}), 400
        
        # 检查关系是否已存在
        existing_relation = Relation.query.filter_by(
            source_item_id=source_item_id,
            target_item_id=target_item_id,
            relation_type=relation_type
        ).first()
        
        if existing_relation:
            return jsonify({'success': False, 'message': '该关系已存在'}), 400
        
        # 创建新关系
        relation = Relation(
            source_item_id=source_item_id,
            target_item_id=target_item_id,
            relation_type=relation_type,
            description=description
        )
        db.session.add(relation)
        db.session.commit()
        
        logger.info(f"创建关系成功: {source_item.name} -> {target_item.name} ({relation_type})")
        return jsonify({'success': True, 'data': relation.to_dict()}), 201
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"创建关系失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/items/<int:item_id>', methods=['DELETE'])
def delete_item(item_id):
    """删除物品"""
    try:
        item = Item.query.get_or_404(item_id)
        db.session.delete(item)
        db.session.commit()
        
        logger.info(f"删除物品成功: {item.name}")
        return jsonify({'success': True, 'message': '物品删除成功'})
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"删除物品失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/relations/<int:relation_id>', methods=['DELETE'])
def delete_relation(relation_id):
    """删除关系"""
    try:
        relation = Relation.query.get_or_404(relation_id)
        db.session.delete(relation)
        db.session.commit()
        
        logger.info(f"删除关系成功: ID {relation_id}")
        return jsonify({'success': True, 'message': '关系删除成功'})
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"删除关系失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.route('/api/graph', methods=['GET'])
def get_graph_data():
    """获取图谱数据（用于前端可视化）"""
    try:
        items = Item.query.all()
        relations = Relation.query.all()
        
        nodes = [{'id': item.id, 'name': item.name} for item in items]
        edges = [
            {
                'source': relation.source_item_id,
                'target': relation.target_item_id,
                'type': relation.relation_type,
                'description': relation.description
            }
            for relation in relations
        ]
        
        return jsonify({
            'success': True,
            'data': {
                'nodes': nodes,
                'edges': edges
            }
        })
    
    except Exception as e:
        logger.error(f"获取图谱数据失败: {e}")
        return jsonify({'success': False, 'message': str(e)}), 500

@app.errorhandler(404)
def not_found(error):
    return jsonify({'success': False, 'message': '资源不存在'}), 404

@app.route('/api/extract-triplets', methods=['POST'])
def extract_triplets():
    """从句子中提取三元组"""
    try:
        data = request.get_json()
        if not data or not data.get('text'):
            return jsonify({'success': False, 'message': '请提供要分析的文本'}), 400
        
        text = data['text'].strip()
        if not text:
            return jsonify({'success': False, 'message': '文本内容不能为空'}), 400
        
        if len(text) > 10000:  # 限制文本长度
            return jsonify({'success': False, 'message': '文本长度不能超过10000字符'}), 400
        
        # 获取是否标准化关系的选项
        normalize_relations = data.get('normalize_relations', True)
        
        logger.info(f"开始提取三元组，文本长度: {len(text)}, 标准化关系: {normalize_relations}")
        
        # 使用知识图谱提取器分析文本
        triplets = kg_extractor.extract_triplets(text, normalize_relations=normalize_relations)
        
        # 格式化三元组结果
        formatted_triplets = []
        for subject, relation, obj in triplets:
            if subject and relation and obj:  # 确保三元组完整
                formatted_triplets.append({
                    'subject': subject,
                    'relation': relation,
                    'object': obj
                })
        
        logger.info(f"从文本提取到 {len(formatted_triplets)} 个有效三元组")
        return jsonify({
            'success': True,
            'triplets': formatted_triplets,
            'count': len(formatted_triplets),
            'original_text': text,
            'normalized': normalize_relations
        })
    
    except Exception as e:
        logger.error(f"三元组提取失败: {e}", exc_info=True)
        return jsonify({'success': False, 'message': f'文本分析失败: {str(e)}'}), 500

@app.route('/api/build-kg-from-text', methods=['POST'])
def build_kg_from_text():
    """从文本自动构建知识图谱"""
    try:
        data = request.get_json()
        if not data or not data.get('text'):
            return jsonify({'success': False, 'message': '请提供要分析的文本'}), 400
        
        text = data['text'].strip()
        if not text:
            return jsonify({'success': False, 'message': '文本内容不能为空'}), 400
        
        if len(text) > 10000:  # 限制文本长度
            return jsonify({'success': False, 'message': '文本长度不能超过10000字符'}), 400
        
        # 获取是否标准化关系的选项
        normalize_relations = data.get('normalize_relations', True)
        
        logger.info(f"开始构建知识图谱，文本长度: {len(text)}, 标准化关系: {normalize_relations}")
        
        # 提取三元组
        triplets = kg_extractor.extract_triplets(text, normalize_relations=normalize_relations)
        
        # 过滤无效三元组
        valid_triplets = []
        for subject, relation, obj in triplets:
            if subject and relation and obj and subject.strip() and obj.strip():
                valid_triplets.append((subject.strip(), relation, obj.strip()))
        
        if not valid_triplets:
            return jsonify({
                'success': True,
                'message': '未从文本中提取到有效的三元组，请尝试使用包含明确关系的句子',
                'stats': {'triplets_extracted': 0, 'items_added': 0, 'relations_added': 0, 'errors_count': 0}
            })
        
        logger.info(f"提取到 {len(valid_triplets)} 个有效三元组")
        
        # 统计信息
        items_added = 0
        relations_added = 0
        errors = []
        
        # 收集所有实体名称
        entities = set()
        for subject, relation, obj in valid_triplets:
            entities.add(subject)
            entities.add(obj)
        
        logger.info(f"准备处理 {len(entities)} 个唯一实体")
        
        # 批量创建实体
        entity_mapping = {}  # 实体名称到ID的映射
        
        for entity_name in entities:
            try:
                # 检查实体是否已存在
                existing_item = Item.query.filter_by(name=entity_name).first()
                if existing_item:
                    entity_mapping[entity_name] = existing_item.id
                    logger.debug(f"实体 '{entity_name}' 已存在，ID: {existing_item.id}")
                else:
                    # 创建新实体
                    new_item = Item(name=entity_name)
                    db.session.add(new_item)
                    db.session.flush()  # 获取ID但不提交
                    entity_mapping[entity_name] = new_item.id
                    items_added += 1
                    logger.debug(f"创建新实体 '{entity_name}', ID: {new_item.id}")
            except Exception as e:
                error_msg = f"创建实体 '{entity_name}' 失败: {str(e)}"
                errors.append(error_msg)
                logger.error(error_msg)
                continue
        
        # 批量创建关系
        for subject, relation, obj in valid_triplets:
            try:
                if subject not in entity_mapping or obj not in entity_mapping:
                    error_msg = f"跳过关系 '{subject} -> {obj}': 实体映射失败"
                    errors.append(error_msg)
                    continue
                
                source_id = entity_mapping[subject]
                target_id = entity_mapping[obj]
                
                # 检查关系是否已存在
                existing_relation = Relation.query.filter_by(
                    source_item_id=source_id,
                    target_item_id=target_id,
                    relation_type=relation
                ).first()
                
                if not existing_relation:
                    # 创建新关系
                    new_relation = Relation(
                        source_item_id=source_id,
                        target_item_id=target_id,
                        relation_type=relation,
                        description=f"从文本自动提取: {subject} {relation} {obj}"
                    )
                    db.session.add(new_relation)
                    relations_added += 1
                    logger.debug(f"创建新关系: {subject} -> {obj} ({relation})")
                else:
                    logger.debug(f"关系已存在: {subject} -> {obj} ({relation})")
                    
            except Exception as e:
                error_msg = f"创建关系 '{subject} -> {obj}' 失败: {str(e)}"
                errors.append(error_msg)
                logger.error(error_msg)
                continue
        
        # 提交所有更改
        db.session.commit()
        
        logger.info(f"自动构建知识图谱完成: 添加 {items_added} 个实体, {relations_added} 个关系")
        
        result = {
            'success': True,
            'message': f'成功从文本构建知识图谱！添加了 {items_added} 个实体和 {relations_added} 个关系',
            'stats': {
                'triplets_extracted': len(valid_triplets),
                'items_added': items_added,
                'relations_added': relations_added,
                'errors_count': len(errors)
            },
            'original_text': text
        }
        
        if errors:
            result['errors'] = errors[:10]  # 只返回前10个错误，避免响应过大
            
        return jsonify(result)
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"从文本构建知识图谱失败: {e}", exc_info=True)
        return jsonify({'success': False, 'message': f'构建知识图谱失败: {str(e)}'}), 500

@app.route('/api/clear-all-data', methods=['DELETE'])
def clear_all_data():
    """删除所有实体和关系数据"""
    try:
        # 删除所有关系（必须先删除关系，因为外键约束）
        relations_count = Relation.query.count()
        Relation.query.delete()
        
        # 删除所有实体
        items_count = Item.query.count()
        Item.query.delete()
        
        # 提交事务
        db.session.commit()
        
        logger.info(f"成功删除所有数据: {items_count} 个实体, {relations_count} 个关系")
        
        return jsonify({
            'success': True,
            'message': f'已成功删除所有数据！删除了 {items_count} 个实体和 {relations_count} 个关系',
            'stats': {
                'items_deleted': items_count,
                'relations_deleted': relations_count
            }
        })
    
    except Exception as e:
        db.session.rollback()
        logger.error(f"删除所有数据失败: {e}", exc_info=True)
        return jsonify({'success': False, 'message': f'删除失败: {str(e)}'}), 500

@app.errorhandler(404)
def not_found(error):
    return jsonify({'success': False, 'message': '资源不存在'}), 404

@app.errorhandler(500)
def internal_error(error):
    return jsonify({'success': False, 'message': '服务器内部错误'}), 500

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
